Greengrass Development Kit CLI(GDK CLI)で AWS IoT Greegrass V2 のコンポーネント開発を効率化する
AWS IoT Greengrass (V2)には、カスタムコンポーネントの開発を支援するために「Greengrass Development Kit CLI(GDK CLI)」というツールがあります。
今回は、その利用方法や動作などを確認してみましたので、ご紹介したいと思います。
これまでの課題
これまでの作業では、カスタムコンポーネントを作って AWS 側にコンポーネントを登録する場合、下記のような作業が必要で少々煩わしいと感じる部分がありました。
- コンポーネントバージョンに合わせたフォルダ階層でS3にアーティファクトを保存
- 例:
s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/HelloWorld.zip
- 例:
- コンポーネントを更新したいときも上記パスの新しいバージョンでフォルダを作成してアーティファクトを再度保存
- (必要に応じて)アーティファクトになる複数ファイルを ZIP 化
- AWS 側でコンポーネントの新バージョンを作成
Greengrass Development Kit CLI(GDK CLI)のメリット
この GDK CLI を使うことで先程記載した作業内容を自動で行ってくれるので、作業効率が大きく改善します。
具体的には下記を実現してくれます。
- コンポーネントのビルド
- S3 へ所定のパス構成でアーティファクトを保存
- 例:
s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/HelloWorld.zip
- 対象の S3 バケットがなければ自動的に作成
- 例:
- AWS 側へ自動的にコンポーネントを作成
- コンポーネント更新時は新しいバージョンのフォルダ構成で新しいアーティファクトを保存
- 更新時はAWS側にも自動的にコンポーネントの新バージョンが作成される
以上の通り GDK CLI を使うことで、コンポーネント作成に関する周辺作業がコマンド1つで実行できるようになるので、コンポーネント開発に注力できるようになります。
GDK CLI でカスタムコンポーネントを作成してみる
公式ドキュメントでは、カスタムコンポーネントの作成方法が分からなかったので、ドキュメントを参考にしつつ試していきたいと思います。
公式ドキュメントは下記ページ以下が対象になります。
GDK CLI インストール
最初に作業 PC に GDK CLI をインストールしましょう。MacOS、Windows、Unixライクなコンピュータにインストール可能です。
前提条件はドキュメントに詳細な記載がありますが、少なくとも下記の環境が必要になります。
- python3.8 以上がインストールされていること
- AWS CLI がインストールされていること(AWS CLI V1 でも可)
- GDK CLI を実行する PC に下記の IAM 権限
s3:CreateBucket
s3:PutObject
greengrass:CreateComponentVersion
greengrass:ListComponentVersions
私は Mac を使っていますが pyenv
の環境で「Python 3.8.7」を用意しました。IAM 権限については Assume Role を設定するなど環境に応じてご用意ください。
GDK CLI のインストールは下記コマンドを実行します。
$ python3 -m pip install git+https://github.com/aws-greengrass/aws-greengrass-gdk-cli.git
下記のように help
の内容が正常に出力されていれば OK です。
$ gdk --help usage: gdk [-h] [-d] [-v] {component} ... Greengrass development kit - CLI for developing AWS IoT GreengrassV2 components. positional arguments: {component} component Initialize, build and publish GreengrassV2 components using this command. optional arguments: -h, --help show this help message and exit -d, --debug Increase command output to debug level -v, --version show program's version number and exit
GDK CLI で初期化する
最初に適当なところで空の作業用ディレクトリを作成します。
このディレクトリ名は S3 に保存する「アーティファクトの ZIP ファイルのファイル名」と同一にする必要があるので注意してください。
$ mkdir GDKTest $ cd GDKTest
次に、コミュニティコンポーネントなどからコンポーネントテンプレートをダウンロードします。
$ gdk component init -l python -t HelloWorld
-t
, --template
オプションでコンポーネントテンプレートを指定します。単純な内容の「HelloWorld」を使うのが分かりやすそうです。
また、今回は python のコンポーネントを作りたいので、-l
, --language
オプションで言語を指定しています。
GDK CLI 構成ファイルを編集する
初期化が終わると下記のようなファイルが展開されます。
. ├── README.md ├── gdk-config.json ├── main.py ├── recipe.yaml ├── src │ └── greeter.py └── tests └── test_greeter.py
編集する必要があるファイルを一つずつ見ていきましょう。
まずはgdk-config.json
です。これは「GDK CLI 構成ファイル」というもので、ビルドシステムの種類や アーティファクトを保存する S3 バケットの指定などを行います。
展開した直後のデフォルトの内容は下記のとおりです。
{ "component": { "com.example.PythonHelloWorld": { "author": "<PLACEHOLDER_AUTHOR>", "version": "NEXT_PATCH", "build": { "build_system": "zip" }, "publish": { "bucket": "<PLACEHOLDER_BUCKET>", "region": "<PLACEHOLDER_REGION>" } } }, "gdk_version": "1.0.0"
これを次のように更新します。
{ "component": { "com.example.MyGDKTest": { "author": "CM-ICHIDA", "version": "NEXT_PATCH", "build": { "build_system": "zip" }, "publish": { "bucket": "gdk-build", "region": "ap-northeast-1" } } }, "gdk_version": "1.0.0" }
更新した箇所は下記です。
author
: コンポーネントの作成者または発行者を指定しますbucket
: アーティファクトを保存する S3 バケット名[BucketName]-[region]-[AWS ACCOUNT ID]
という形式のバケットにアーティファクトを保存します- 構成ファイルで指定した名前が上記の
[BucketName]
に入ります。 - (上記の場合、
gdk-build-ap-northeast-1-XXXXXXXXXXXX
というバケットになる)
- 構成ファイルで指定した名前が上記の
- 存在しなければ自動的に作成されます
region
: コンポーネントを公開するリージョン
なお、build_system
は更新していません。python などインタプリタ型の言語の場合は zip
を指定します。言語に応じて「Maven」や「Gradle」などを指定することができたり、カスタム指定も可能です。
それぞれの値に関する詳細については下記ドキュメントを参考にしてください。
レシピを編集する
次はコンポーネントのレシピであるrecipe.yaml
を修正します。
デフォルトでは下記のとおりです。GDK CLI 特有の記載はありませんが、変数になっている項目については先程の構成ファイルやGDK CLI により利用されるものと推測されます。
--- RecipeFormatVersion: "2020-01-25" ComponentName: "{COMPONENT_NAME}" ComponentVersion: "{COMPONENT_VERSION}" ComponentDescription: "This is simple Hello World component written in Python." ComponentPublisher: "{COMPONENT_AUTHOR}" ComponentConfiguration: DefaultConfiguration: Message: "World" Manifests: - Platform: os: all Artifacts: - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/HelloWorld.zip" Unarchive: ZIP Lifecycle: Run: "python3 -u {artifacts:decompressedPath}/HelloWorld/main.py {configuration:/Message}"
このレシピを下記のように編集します。
--- RecipeFormatVersion: "2020-01-25" ComponentName: "{COMPONENT_NAME}" ComponentVersion: "{COMPONENT_VERSION}" ComponentDescription: "This is GDK Test component written in Python." ComponentPublisher: "{COMPONENT_AUTHOR}" ComponentConfiguration: DefaultConfiguration: Message: "GDK" Manifests: - Platform: os: all Artifacts: - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/GDKTest.zip" Unarchive: ZIP Lifecycle: Run: "python3 -u {artifacts:decompressedPath}/GDKTest/main.py {configuration:/Message}"
Artifacts
の URI
にあるアーティファクトのファイル名を作業用ディレクトリと同じものに変更しておきます。このファイル名と作業用ディレクトリが異なっていると次の作業であるビルド時にエラーになります。
また、ComponentDescription
とDefaultConfiguration
のMessage
も適当に変えてみました。
コンポーネントのプログラムを編集する
最後にデバイス上で動作するコンポーネントの実体である Python スクリプト(main.py
)を編集します。 サンプルの HelloWorld スクリプトは下記のような内容です。
import sys import src.greeter as greeter def main(): args = sys.argv[1:] if len(args) == 1: print(greeter.get_greeting(args[0])) if __name__ == "__main__": main()
これを適当な内容で変更します。適宜やりたいことに合わせてスクリプトを書いてください。今回は下記の様な内容にしました。
import sys import datetime import time message = "Hello, %s! Current time: %s." % (sys.argv[1], datetime.datetime.now()) while(True): # Print the message to stdout. print(message) # Append the message to the log file. with open('/tmp/Greengrass_GDKTest.log', 'a') as f: print(message, file=f) time.sleep(5)
ビルドする
準備が終わったのでビルドします。
$ gdk component build
正常にビルドできれば下記のようなメッセージが表示されます。
[2022-01-21 11:52:01] INFO - Getting project configuration from gdk-config.json [2022-01-21 11:52:01] INFO - Found component recipe file 'recipe.yaml' in the project directory. [2022-01-21 11:52:01] INFO - Building the component 'com.example.MyGDKTest' with the given project configuration. [2022-01-21 11:52:01] INFO - Using 'zip' build system to build the component. [2022-01-21 11:52:01] WARNING - This component is identified as using 'zip' build system. If this is incorrect, please exit and specify custom build command in the 'gdk-config.json'. [2022-01-21 11:52:01] INFO - Zipping source code files of the component. [2022-01-21 11:52:01] INFO - Copying over the build artifacts to the greengrass component artifacts build folder. [2022-01-21 11:52:01] INFO - Updating artifact URIs in the recipe. [2022-01-21 11:52:01] INFO - Creating component recipe in '/your-folder-path/GDKTest/greengrass-build/recipes'.
ビルド後のディレクトリの内容は下記のようになります。greengrass-build
ディレクトリやzip-build
ディレクトリが作成されているのが分かります。
. ├── README.md ├── gdk-config.json ├── greengrass-build │ ├── artifacts │ │ └── com.example.MyGDKTest │ │ └── NEXT_PATCH │ │ └── GDKTest.zip │ └── recipes │ └── recipe.yaml ├── main.py ├── recipe.yaml ├── src │ └── greeter.py ├── tests │ └── test_greeter.py └── zip-build ├── GDKTest │ ├── README.md │ ├── main.py │ ├── src │ │ └── greeter.py │ └── tests │ └── test_greeter.py └── GDKTest.zip
パブリッシュする
ビルドが正常に完了すれば、次はいよいよ AWS へコンポーネントを作成することになります。この際に先に掲載した IAM 権限が必要になるので、必要に応じて用意してください。
パブリッシュ自体は下記で実行します。
$ gdk component publish
正常にパブリッシュできれば下記のようなメッセージが出力されます。
メッセージを見ると構成ファイルに基づき gdk-build-ap-northeast-1-[AWS_ACCOUNT_ID]
という S3 バケットが作成されたことが分かります。また、com.example.MyGDKTest
というプライベートコンポーネントがバージョン1.0.0
にて AWS 側に作成されたことも分かります。
[2022-01-21 11:53:52] INFO - Getting project configuration from gdk-config.json [2022-01-21 11:53:52] INFO - Found component recipe file 'recipe.yaml' in the project directory. [2022-01-21 11:53:52] INFO - Found credentials in environment variables. [2022-01-21 11:53:53] INFO - No private version of the component 'com.example.MyGDKTest' exist in the account. Using '1.0.0' as the next version to create. [2022-01-21 11:53:53] INFO - Publishing the component 'com.example.MyGDKTest' with the given project configuration. [2022-01-21 11:53:53] INFO - Uploading the component built artifacts to s3 bucket. [2022-01-21 11:53:53] INFO - Uploading component artifacts to S3 bucket: gdk-build-ap-northeast-1-[AWS-ACCOUNT-ID]. If this is your first time using this bucket, add the 's3:GetObject' permission to each core device's token exchange role to allow it to download the component artifacts. For more information, see https://docs.aws.amazon.com/greengrass/v2/developerguide/device-service-role.html. [2022-01-21 11:53:54] INFO - Not creating an artifacts bucket as it already exists. [2022-01-21 11:53:54] INFO - Updating the component recipe com.example.MyGDKTest-1.0.0. [2022-01-21 11:53:54] INFO - Creating a new greengrass component com.example.MyGDKTest-1.0.0 [2022-01-21 11:53:55] INFO - Created private version '1.0.0' of the component in the account.'com.example.MyGDKTest'.
S3 バケットを確認するとパブリッシュしたコンポーネントのアーティファクト用のフォルダが作成されていることが確認できます。
このフォルダにアーティファクトの ZIP ファイルが保存されていますが、バージョンが1.0.0
として保存されていることが分かります。
AWS IoT Greengrass のコンソール画面を見ると、パブリッシュしたコンポーネントが登録されていることを確認できました!
コンポーネントをデプロイしてみる
GDK CLI がやってくれることは AWS へコンポーネントを作成することまでですが、せっかくなのでデバイスにデプロイしてみましょう。
デプロイ作業はいつもどおりの作業になります。さきほど GDK CLI で作成したコンポーネントを選択してデプロイします。
デプロイが正常に完了すると、コンポーネントログ(/greengraass/v2/logs/com.example.MyGDKTest.log
)にメッセージが5秒ごとに出力されていることが分かります。
コンポーネントのスクリプトで出力先を指定した /tmp/Greengrass_GDKTest.log
にもメッセージを確認できました。
コンポーネントを GDK CLI で更新する
実は、先程デプロイしたスクリプトは一部ミスがあり、出力メッセージにあるタイムスタンプが更新されていませんでした。これを修正したコンポーネントを GDK CLI で更新してデプロイし直したいと思います。
作業 PC で先程のmain.py
を次のように修正します。
import sys import datetime import time while(True): # Print the message to stdout. message = "Hello, %s! Current time: %s." % (sys.argv[1], datetime.datetime.now()) print(message) # Append the message to the log file. with open('/tmp/Greengrass_GDKTest.log', 'a') as f: print(message, file=f) time.sleep(5)
GDK CLI 構成ファイルやレシピなど、他のファイルは修正する必要がないので、このままビルドします。
$ gdk component build
ビルド後のファイル構成は特に変わりませんが、タイムスタンプを付与した状態で見ると、greengrass-build
ディレクトリやzip-build
のタイムスタンプが更新されていました。
(最初にビルドしたのは午前11時台でしたが、再ビルドは14時14分頃に実施しました)
$ tree -AD . ├── [Jan 21 11:16] README.md ├── [Jan 21 11:31] gdk-config.json ├── [Jan 21 14:14] greengrass-build │ ├── [Jan 21 14:14] artifacts │ │ └── [Jan 21 14:14] com.example.MyGDKTest │ │ └── [Jan 21 14:14] NEXT_PATCH │ │ └── [Jan 21 14:14] GDKTest.zip │ └── [Jan 21 14:14] recipes │ └── [Jan 21 14:14] recipe.yaml ├── [Jan 21 14:12] main.py ├── [Jan 21 11:45] recipe.yaml ├── [Jan 21 11:16] src │ └── [Jan 21 11:16] greeter.py ├── [Jan 21 11:16] tests │ └── [Jan 21 11:16] test_greeter.py └── [Jan 21 14:14] zip-build ├── [Jan 21 14:14] GDKTest │ ├── [Jan 21 11:16] README.md │ ├── [Jan 21 14:12] main.py │ ├── [Jan 21 11:16] src │ │ └── [Jan 21 11:16] greeter.py │ └── [Jan 21 11:16] tests │ └── [Jan 21 11:16] test_greeter.py └── [Jan 21 14:14] GDKTest.zip
次にパブリッシュします。
$ gdk component publish
2回目のパブリッシュが完了すると、S3 上のアーティファクトの保存先が新しいバージョン(1.0.1
)で作成されていました。
AWS 側のコンソールでもコンポーネントの新バージョン(1.0.1
)が作成されていました。
この新しいバージョンのコンポーネントを再度デプロイして正常に5秒ごとのタイムスタンプが出力されるようになりました。
以上のように、「コンポーネントの更新〜新バージョンの作成」の作業も非常に簡単になりました。
最後に
GDK CLI により面倒な作業を自動化することでコンポーネント開発に専念できるようになり、開発スピードも改善できることが分かりました。
とても便利なツールなので、ぜひ使ってみていただければと思います!!